#include "error.h"
#include "lexical.h"
#include <stdio.h>
#include <assert.h>
#include "parser.h"

int warn_num_g = 0; // 警告个数
int err_num_g = 0;  // 错误个数

void show_error_num(void)
{
    printf("warning: %d, error: %d\n", warn_num_g, err_num_g);
}

/*
    打印词法错误
*/

void lex_err(lex_err_code_e code, err_level_e lvl)
{  
    /* 和 lex_err_code_e 一一对应 */
    const char *lex_err_table[] = {
        "标识符过长",           // ID_2_LONG
        "数字过长",             // NUM_2_LONG
        "字符串过长",           // STR_2_LONG
        "多行注释没有正常结束",  // COMMENT_NO_END
        "字符串缺少右引号",     // STR_INCOMPLT
        "字符不完整",           // CHARA_INCOMPLT
        "逻辑或不完整",         // OR_NO_PAIR
        "无法识别的词法记号",    // UNRECOGNIZED_TOKEN
        "字符常量为空",         // EMPTY_CHARA   
        "未知转义字符",         // UNKNOW_ESCAPE_SEQUENCE
    };

    assert(LEX_ERR_CODE_NUM == ARR_ELEM_CNT(lex_err_table));

    const char *level_str;
    if(lvl == ERROR) {
        level_str = HI_RED"error:"CLOSE;
        err_num_g++;
    } else {
        level_str = HI_YEL"warning:"CLOSE;
        warn_num_g++; 
    }
        
    const char *file_name = scanner_get_file_name();
    int line = scanner_get_line_num();
    int col = scanner_get_col_num();
    char ch = scanner_get_cur_ch();

    if (code == ID_2_LONG) {
        printf("%s:%d:%d: %s %s, 仅识别标识符：%s\n", 
            file_name, line, col, level_str, lex_err_table[code], scanner_get_token_id());
    } else if (code == STR_2_LONG) {
        printf("%s:%d:%d: %s %s, 仅识别字符串：%s\n", 
            file_name, line, col, level_str, lex_err_table[code], scanner_get_token_str());
    } else if (code == NUM_2_LONG) {
        printf("%s:%d:%d: %s %s, 仅识别数字：%d\n", 
            file_name, line, col, level_str, lex_err_table[code], scanner_get_token_num());
    } else if (code == UNRECOGNIZED_TOKEN) {
        printf("%s:%d:%d: %s %s:\'%c\'(ASCII:%d)\n", file_name, line, col, level_str,
               lex_err_table[code], ch, ch);
    } else {
        printf("%s:%d:%d: %s %s\n", file_name, line, col, level_str, lex_err_table[code]);
    }
}



/*
	打印语法错误
*/
void syn_err(syn_err_code_e code,  err_level_e lvl, int cause, const char *name)
{	
	const char *syn_err_code_tab[]=
	{
		"类型",
        "标识符",
        "(",
        ")",
        "[",
        "]",                 // expected ‘]’ before ‘;’
        "{",                 //   expected ‘{’
        "}",                 //   expected ‘}’
        ",",
        ";",
        "=",
        ":",
        "while",              // expected 'while'
        "数组的元素个数是负数或零",  // error: size of array ‘xx’ is negative
        "缺少表达式或常量",
        "缺少常量",
        "禁止函数嵌套定义", 
        "数组长度必须是常量",
        "case label 必须是整形常量",
        "只能是语句(statement), 不能是声明(declaration)",
        "忽略token ",

	};
    assert(SYN_ERR_CODE_NUM == ARR_ELEM_CNT(syn_err_code_tab));

    const char *level_str;
    if(lvl == ERROR) {
        level_str = HI_RED"error:"CLOSE;
        err_num_g++;
    } else {
        level_str = HI_YEL"warning:"CLOSE;
        warn_num_g++; 
    }
	        
    const char *file_name = scanner_get_file_name();
    int line = scanner_get_line_num();
    int col = scanner_get_col_num();
    char ch = scanner_get_cur_ch();

    
	if(cause == LOST) {
		printf("%s:%d:%d: %s 在 %s 之前丢失 \'%s\'\n", file_name, line, col, level_str, 
                scanner_get_token_name(), syn_err_code_tab[code]);
    } else if(cause == NOT_MATCH) {
        printf("%s:%d:%d: %s 在 %s 处没有正确匹配 \'%s\'\n", file_name, line, col, level_str, 
                scanner_get_token_name(), syn_err_code_tab[code]);

    } else {
        switch(code) {
            case ARR_SIZE_NEGATIVE_OR_ZERO:
            case ARR_SIZE_NO_CONSTANT:
                printf("%s:%d:%d: %s 数组\'%s\': %s\n", file_name, line, col, level_str, 
                name, syn_err_code_tab[code]);
                break;

            case FORBIDS_NESTED_FUNCTIONS:
                printf("%s:%d:%d: %s 函数\'%s\': %s\n", file_name, line, col, level_str, 
                name, syn_err_code_tab[code]);
                break;
            case EXPECTED_LITERAL_OR_EXPR:
                printf("%s:%d:%d: %s 在\'%s\'之前: %s\n", file_name, line, col, level_str, 
                scanner_get_token_name(), syn_err_code_tab[code]);
                break;

            case CASE_LABEL_NOT_INT_CONSTANT:
            case NEED_STATEMENT:
                printf("%s:%d:%d: %s : %s\n", file_name, line, col, level_str,  syn_err_code_tab[code]);
                break;
 
            case EXPECTED_LITERAL:   
                printf("%s:%d:%d: %s 在\'%s\'之前: %s\n", file_name, line, col, level_str, 
                scanner_get_token_name(), syn_err_code_tab[code]);
                break;
    
            case IGNORE_TOKEN:
                printf("%s:%d:%d: %s %s'%s'\n", file_name, line, col, level_str, syn_err_code_tab[code], name);

            default:
                
                break;
        }
         
    }
	
}


void recovery(bool cond, syn_err_code_e code,  err_level_e lvl)
{
	if(cond)	/* 在给定的集合内 */
		syn_err(code, lvl, LOST, NULL);
	else{
		syn_err(code, lvl, NOT_MATCH, NULL);
		next_token(); // 这才是关键
	}
}


void recovery_until_type(bool cond, syn_err_code_e code,  err_level_e lvl)
{    
	if(cond)	/* 在给定的集合内 */
		syn_err(code, lvl, LOST, NULL);
	else{
		syn_err(code, lvl, NOT_MATCH, NULL);
        syn_err(IGNORE_TOKEN, WARNING, OTHER, scanner_get_token_name());
        next_token();
        while(  (token_g != FILE_END) && (!(TYPE_FIRST))){
            syn_err(IGNORE_TOKEN, WARNING, OTHER, scanner_get_token_name());
            next_token(); 

        }   
	}
}